//
//  QRCodesManager.m
//  QRCodeManager
//
//  Created by Cosmin Stirbu on 4/16/13.
//  Copyright (c) 2013 Cosmin Stirbu. All rights reserved.
//

#import "QRCodesManager.h"
#import "CoreDataManager.h"
#import "QRWiFi.h"
#import "QREvent.h"
#import "QRUrl.h"
#import "QRContact.h"
#import "QRLocation.h"
#import "QROther.h"
#import "QRWiFiParser.h"
#import "QREventParser.h"
#import "QRContactParser.h"
#import "QRLocationParser.h"

// Regular Expressions For Checking Type

NSString * const WI_FI_REG_EX = @"WIFI:S:.*;T:((WEP)|(WPA)|(nopass));P:.*;;";
NSString * const EVENT_REG_EX = @"BEGIN:VEVENT(.|\\n)*END:VEVENT";
NSString * const GEOLOCATION_REG_EX = @"geo:[-0-9\\.]*,[-0-9\\.]*";
NSString * const CONTACT_REG_EX = @"MECARD:(.|\\n)*;;";

@implementation QRCodesManager

+ (QRCodesManager *)sharedInstance
{
    static QRCodesManager *sharedInstance = nil;
    static dispatch_once_t onceToken; // Lock
    dispatch_once(&onceToken, ^{  // This code is called at most once
        sharedInstance = [[QRCodesManager alloc] init];
    });
    return sharedInstance;
}

- (id)init {
    self = [super init];
    if (self) {
        _groupedQRCodes = [NSMutableDictionary new];
        NSArray *qrCodes = [self fetchQRCodes];
        for (QRCode *qrCode in qrCodes) {
            [self addQrCode:qrCode];
        }
    }
    return self;
}

- (QRCode *)qrCodeFromString:(NSString *)qrCodeString withName:(NSString *)name {
    qrCodeString = [qrCodeString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
    if ([self isWiFi:qrCodeString]) {
        // WI-FI
        QRWiFiParser *qrParser = [[QRWiFiParser alloc] initWithData:qrCodeString];
        QRWiFi *qrWifi = [qrParser qrWiFi];
        if (qrWifi) {
            qrWifi.name = name;
            qrWifi.qrType = QRWiFiType;
            qrWifi.typeName = NSLocalizedString(@"wi_fi_category", nil);
            [self addQrCode:qrWifi];
            return qrWifi;
        }
    }
    if ([self isEvent:qrCodeString]) {
        // Event
        QREventParser *qrPraser = [[QREventParser alloc] initWithData:qrCodeString];
        QREvent *qrEvent = [qrPraser qrEvent];
        if (qrEvent) {
            qrEvent.name = name;
            qrEvent.qrType = QREventType;
            qrEvent.typeName = NSLocalizedString(@"event_category", nil);
            [self addQrCode:qrEvent];
            return qrEvent;
        }
    }
    if ([self isLocation:qrCodeString]) {
        // Location
        QRLocationParser *qrParser = [[QRLocationParser alloc] initWithData:qrCodeString];
        QRLocation *qrLocation = [qrParser qrLocation];
        if (qrLocation) {
            qrLocation.qrType = QRLocationType;
            qrLocation.name = name;
            qrLocation.typeName = NSLocalizedString(@"location_category", nil);
            [self addQrCode:qrLocation];
            return qrLocation;
        }
    }
    if ([self isContact:qrCodeString]) {
        // Contact
        QRContactParser *qrParser = [[QRContactParser alloc] initWithData:qrCodeString];
        QRContact *qrContact = [qrParser qrContact];
        if (qrContact){
            qrContact.qrType = QRContactType;
            qrContact.name = name;
            qrContact.typeName = NSLocalizedString(@"contacts_category", nil);
            [self addQrCode:qrContact];
            return qrContact;
        }
    }
    if ([self isURL:qrCodeString]) {
        // URL
        QRUrl *qrUrl = (QRUrl *) [NSEntityDescription insertNewObjectForEntityForName:@"QRUrl" inManagedObjectContext:[CoreDataManager sharedInstance].managedObjectContext];
        qrUrl.url = qrCodeString;
        qrUrl.content = qrCodeString;
        qrUrl.name = name;
        qrUrl.qrType = QRURLType;
        qrUrl.typeName = NSLocalizedString(@"url_category", nil);
        [self addQrCode:qrUrl];
        return qrUrl;
    }
    // Other QRCode
    QROther *qrOther = (QROther *)[NSEntityDescription insertNewObjectForEntityForName:@"QROther" inManagedObjectContext:[CoreDataManager sharedInstance].managedObjectContext];
    qrOther.qrType = QROtherType;
    qrOther.content = qrCodeString;
    qrOther.name = name;
    qrOther.typeName = NSLocalizedString(@"other_category", nil);
    [self addQrCode:qrOther];
    
    return qrOther;
}

- (NSDictionary *)groupedQrCodes {
    return _groupedQRCodes;
}

- (NSArray *)sortedKeys {
    NSMutableArray *mutableKeys = [NSMutableArray arrayWithArray:[[_groupedQRCodes allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)]];
    if ([mutableKeys containsObject:NSLocalizedString(@"other_category", nil)]) {
        [mutableKeys removeObject:NSLocalizedString(@"other_category", nil)];
        [mutableKeys addObject:NSLocalizedString(@"other_category", nil)];
    }
    return mutableKeys;
}

- (void)addQrCode:(QRCode *)qrCode {
    NSMutableArray *qrCodes = [_groupedQRCodes objectForKey:qrCode.typeName];
    if (qrCodes) {
        [qrCodes addObject:qrCode];
    } else {
        qrCodes = [[NSMutableArray alloc] initWithObjects:qrCode, nil];
        [_groupedQRCodes setObject:qrCodes forKey:qrCode.typeName];
    }
    [[CoreDataManager sharedInstance] saveContext];
}

- (void)deleteQrCode:(QRCode *)qrCode {
    [[CoreDataManager sharedInstance].managedObjectContext deleteObject:qrCode];
    NSMutableArray *qrCodes = [_groupedQRCodes objectForKey:qrCode.typeName];
    [qrCodes removeObject:qrCode];
    if ([qrCodes count] == 0) {
        [_groupedQRCodes removeObjectForKey:qrCode.typeName];
    }
    [[CoreDataManager sharedInstance] saveContext];
}

- (NSIndexPath *)indexPathOfQrCode:(QRCode *)qrCode {
    NSArray *allKeys = [self sortedKeys];
    NSInteger categoryIndex = [allKeys indexOfObject:qrCode.typeName];
    
    NSMutableArray *qrCodes = [_groupedQRCodes objectForKey:qrCode.typeName];
    NSInteger qrCodeIndex = [qrCodes indexOfObject:qrCode];
    
    return  [NSIndexPath indexPathForRow:qrCodeIndex inSection:categoryIndex];
}

- (NSArray *)fetchQRCodes {
    NSEntityDescription *entityDescription = [NSEntityDescription
                                              entityForName:@"QRCode" inManagedObjectContext:[CoreDataManager sharedInstance].managedObjectContext];
    NSFetchRequest *request = [NSFetchRequest new];
    [request setEntity:entityDescription];
    return [[CoreDataManager sharedInstance].managedObjectContext executeFetchRequest:request error:nil];
}

#pragma mark - QRCode type checking

- (BOOL)isWiFi:(NSString *)qrData{
    return [self validateString:qrData withRegularExpression:WI_FI_REG_EX];
}

- (BOOL)isEvent:(NSString *)qrData {
    return [self validateString:qrData withRegularExpression:EVENT_REG_EX];
}

- (BOOL)isLocation:(NSString *)qrData {
    return [self validateString:qrData withRegularExpression:GEOLOCATION_REG_EX];
}

- (BOOL)isURL:(NSString *)qrData {
    NSURLRequest *req = [NSURLRequest requestWithURL:[NSURL URLWithString:qrData]];
    return [NSURLConnection canHandleRequest:req];
}

- (BOOL)isContact:(NSString *)qrData {
    return [self validateString:qrData withRegularExpression:CONTACT_REG_EX];
}

- (BOOL)validateString:(NSString *)aString withRegularExpression:(NSString *)aRegexp {
	NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", aRegexp];
	return [predicate evaluateWithObject:aString];
}
@end
